/**
 * @file signalTemplate.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-02-28
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#pragma once
#include <functional>
#include <map>
#include <mutex>

#include "basic/trace.h"

namespace wheels {

template <typename R, typename... ArgTypes>
class CSignalTemplate {
   public:
    using funcType = R(ArgTypes...);
    using funcPtrType = funcType *;
    using Proc = std::function<funcType>;

   public:
    explicit CSignalTemplate(uint32_t num) : m_maxNum(num) {}
    ~CSignalTemplate() = default;

    bool isAttach(const char *name);
    bool attach(const char *name, Proc proc);
    bool detach(const char *name);
    void operator()(ArgTypes... args);

   private:
    uint32_t m_maxNum;
    std::mutex m_mutex;
    std::map<const char *, Proc> m_siganlMap;
};

template <typename R, typename... ArgTypes>
bool CSignalTemplate<R, ArgTypes...>::isAttach(const char *name) {
    std::lock_guard<std::mutex> guard(m_mutex);
    if (m_siganlMap.find(name) != m_siganlMap.end()) {
        return true;
    }
    return false;
}

template <typename R, typename... ArgTypes>
bool CSignalTemplate<R, ArgTypes...>::attach(const char *name, Proc proc) {
    std::lock_guard<std::mutex> guard(m_mutex);
    if (m_siganlMap.size() >= m_maxNum) {
        trace_err("not free slot\n");
        return false;
    }

    auto ret = m_siganlMap.insert(std::make_pair(name, proc));
    if (false == ret.second) {
        trace_err("{%s} has attached\n", name);
    }
    return ret.second;
}

template <typename R, typename... ArgTypes>
bool CSignalTemplate<R, ArgTypes...>::detach(const char *name) {
    std::lock_guard<std::mutex> guard(m_mutex);
    m_siganlMap.erase(name);
    return true;
}

template <typename R, typename... ArgTypes>
void CSignalTemplate<R, ArgTypes...>::operator()(ArgTypes... rest) {
    std::lock_guard<std::mutex> guard(m_mutex);
    for (auto iter = m_siganlMap.begin(); iter != m_siganlMap.end(); ++iter) {
        (iter->second)(rest...);
    }
}

}  // namespace wheels
